package com.xjrsoft.module.organization.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.annotation.XjrLog;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.IsReadTypeEnum;
import com.xjrsoft.common.enums.YesOrNoEnum;
import com.xjrsoft.common.handler.FormContentStyleStrategy;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.model.result.R;
import com.xjrsoft.common.utils.ExcelUtil;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.common.utils.TreeUtil;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.magicapi.entity.InterfaceAuth;
import com.xjrsoft.module.oa.entity.Message;
import com.xjrsoft.module.organization.dto.*;
import com.xjrsoft.module.organization.entity.*;
import com.xjrsoft.module.organization.service.*;
import com.xjrsoft.module.organization.utils.OrganizationUtil;
import com.xjrsoft.module.organization.vo.*;
import com.xjrsoft.module.system.dto.SwitchPostDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 岗位 前端控制器
 * </p>
 *
 * @author tzx
 * @since 2022-03-02
 */
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/post")
@Api(value = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/post", tags = "岗位")
@AllArgsConstructor
public class PostController {

    private final IPostService postService;

    private final IUserService userService;

    private final IDepartmentService departmentService;

    private final RedisUtil redisUtil;

    private final IUserPostRelationService userPostRelationService;
    private final IUserDeptRelationService userDeptRelationService;


    @GetMapping(value = "/list")
    @ApiOperation(value = "岗位列表(不分页)")
    public R list(String keyword) {
        List<Post> list = postService.list(Wrappers.lambdaQuery(Post.class)
                .like(StrUtil.isNotBlank(keyword), Post::getName, keyword)
                .or()
                .like(StrUtil.isNotBlank(keyword), Post::getCode, keyword)
                .select(Post.class, x -> VoToColumnUtil.fieldsToColumns(PostListVo.class).contains(x.getProperty()))
                .orderByAsc(Post::getSortCode));

        List<PostListVo> postListVos = BeanUtil.copyToList(list, PostListVo.class);
        return R.ok(postListVos);
    }

    @GetMapping(value = "/page")
    @ApiOperation(value = "岗位列表(分页)")
    public R page(@Valid PostPageDto dto) {

        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()), Post::getName, dto.getKeyword())
//                .eq(Post::getEnabledMark, YesOrNoEnum.YES.getCode())
                .eq(ObjectUtil.isNotEmpty(dto.getDepartmentId()),Post::getDeptId,dto.getDepartmentId())
                .like(StrUtil.isNotBlank(dto.getKeyword()), Post::getCode, dto.getKeyword())
                .like(StrUtil.isNotBlank(dto.getName()), Post::getName, dto.getName())
                .like(StrUtil.isNotBlank(dto.getCode()), Post::getCode, dto.getCode())
                .like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Post::getEnabledMark, dto.getEnabledMark())
                .select(Post.class, x -> VoToColumnUtil.fieldsToColumns(PostPageVo.class).contains(x.getProperty()))
                .orderByAsc(Post::getSortCode);

        IPage<Post> page = postService.page(ConventPage.getPage(dto), queryWrapper);
        PageOutput<PostPageVo> pageOutput = ConventPage.getPageOutput(page, PostPageVo.class);
        return R.ok(pageOutput);
    }

    @GetMapping(value = "/info")
    @ApiOperation(value = "根据id查询机构信息")
    public R info(@RequestParam Long id) {
        Post post = postService.getById(id);
        if (post == null) {
            R.error("找不到此岗位！");
        }
        return R.ok(BeanUtil.toBean(post, PostVo.class));
    }

    @GetMapping(value = "/info/multi")
    @ApiOperation(value = "批量查询岗位信息")
    public R multiInfo(@RequestParam String ids) {
        List<Post> postList = new ArrayList<>();
        if (StrUtil.isNotBlank(ids)){
            //pgsql需要强转成Long类型数据
            List<Long> longList = Arrays.stream(ids.split(StringPool.COMMA))
                    .map(Long::parseLong)
                    .collect(Collectors.toList());
            LambdaQueryWrapper<Post> queryWrapper = Wrappers.lambdaQuery(Post.class).in(Post::getId,  longList);
            postList = postService.list(queryWrapper);
            if (postList == null) {
                R.error("找不到此岗位！");
            }
        }
        return R.ok(BeanUtil.copyToList(postList, PostVo.class));
    }

    @PostMapping
    @ApiOperation(value = "新增岗位")
    public R add(@Valid @RequestBody AddPostDto dto) {
        long count = postService.count(Wrappers.<Post>query().lambda().eq(Post::getCode, dto.getCode()));
        if (count > 0) {
            return R.error("岗位编码已经存在！");
        }
        Post post = BeanUtil.toBean(dto, Post.class);
        postService.save(post);
        CompletableFuture.runAsync(() -> {
            List<Post> list = postService.list();
            redisUtil.set(GlobalConstant.POST_CACHE_KEY, list);
        });

        return R.ok(true);
    }

    @PutMapping
    @ApiOperation(value = "修改岗位")
    public R update(@Valid @RequestBody UpdatePostDto dto) {

        long count = postService.count(Wrappers.<Post>query().lambda()
                .eq(Post::getCode, dto.getCode())
                .ne(Post::getId, dto.getId()));

        if (count > 0) {
            return R.error("岗位编码已经存在！");
        }

        Post post = BeanUtil.toBean(dto, Post.class);
        postService.updateById(post);
        CompletableFuture.runAsync(() -> {
            List<Post> list = postService.list();
            redisUtil.set(GlobalConstant.POST_CACHE_KEY, list);
        });
        return R.ok(true);
    }

    @DeleteMapping
    @ApiOperation(value = "删除")
    @XjrLog(value = "删除岗位")
    public R delete(@Valid @RequestBody List<Long> ids) {
        //删除岗位时，需要判断，此岗位下是不是存在人员，存在人员就不能删除
        //查询到所有的用户数据
        List<UserPostRelation> userPostRelationList = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
        });
        //拿ids进行过滤，如果存在，就不能删除
        List<UserPostRelation> users = userPostRelationList.stream().filter(u -> ids.contains(u.getPostId())).collect(Collectors.toList());

        if (users.size()>0){
            return R.error("此岗位下存在用户！");
        }
        postService.removeBatchByIds(ids);
        CompletableFuture.runAsync(() -> {
            List<Post> list = postService.list();
            redisUtil.set(GlobalConstant.POST_CACHE_KEY, list);
        });
        return R.ok(true);
    }

    @GetMapping(value = "/tree")
    @ApiOperation(value = "岗位机构树")
    @XjrLog(value = "岗位展示")
    public R tree(PostTreeDto dto) {
        //如果deptId有子集组织，也需要把子集组织的用户一起显示出来
//        List<Long> deptChild = new ArrayList<>();
//        if(ObjectUtil.isNotEmpty(dto.getDeptId())){
//            List<Long> deptIds = new ArrayList<>();
//            deptIds.add(dto.getDeptId());
//            List<Department> list = departmentService.list();
//            //先将list集合里面禁用的进行过滤
//            List<Department> unEnabledMarkList = OrganizationUtil.getUnEnabledMarkList(list);
//            //获取该部门下所有的子节点
//            deptChild = OrganizationUtil.getDeptChild(deptIds, unEnabledMarkList);
//            deptChild.addAll(deptIds);
//        }

        LambdaQueryWrapper<Post> queryWrapper = Wrappers.<Post>query().lambda()
                .eq(ObjectUtil.isNotEmpty(dto.getDeptId()), Post::getDeptId, dto.getDeptId())
                .like(StrUtil.isNotBlank(dto.getName()), Post::getName, dto.getName())
                .like(StrUtil.isNotBlank(dto.getCode()), Post::getCode, dto.getCode())
                .like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Post::getEnabledMark, dto.getEnabledMark())
                .select(Post.class, x -> VoToColumnUtil.fieldsToColumns(PostTreeVo.class).contains(x.getProperty()))
                .last(StrUtil.isNotBlank(dto.getField()), GlobalConstant.ORDER_BY + StringPool.SPACE + dto.getField() + StringPool.SPACE + ConventPage.getOrder(dto.getOrder()))
                .orderByAsc(StrUtil.isBlank(dto.getField()), Post::getSortCode);

        List<Post> list = postService.list(queryWrapper);
        List<PostTreeVo> voList = BeanUtil.copyToList(list, PostTreeVo.class);
        List<PostTreeVo> treeVoList = TreeUtil.build(voList);
        for (PostTreeVo postTreeVo : treeVoList) {
            if (postTreeVo.getParentId()==0){
                postTreeVo.setParentId(null);
            }
        }
        return R.ok(treeVoList);
    }

    @GetMapping(value = "/get-post-user")
    @ApiOperation(value = "根据岗位id查询所拥有的用户")
    public R getUserByPostId(@RequestParam Long id) {
        List<UserPostRelation> list = userPostRelationService.list(Wrappers.<UserPostRelation>query().lambda().eq(UserPostRelation::getPostId, id));
        if (CollectionUtils.isEmpty(list)) {
            return R.ok(new ArrayList<>());
        }
        List<Long> userIds = list.stream().map(UserPostRelation::getUserId).collect(Collectors.toList());
        List<User> users = userService.list(Wrappers.<User>query().lambda().in(User::getId, userIds).select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPostVo.class).contains(x.getProperty())));
        List<UserPostVo> userPostVos = BeanUtil.copyToList(users, UserPostVo.class);
        return R.ok(userPostVos);
    }


    @PutMapping(value = "/update-user-post-batch")
    @ApiOperation(value = "添加岗位下的人员")
    public R updatePostIdByUserId(@RequestBody UpdateUserPostDto dto){
        //添加岗位下的人员以及人员的组织
        return R.ok(userPostRelationService.addPostUser(dto));
    }

    @PostMapping("/switch-post")
    @ApiOperation(value = "切换岗位")
    public R switchPost(@Valid @RequestBody SwitchPostDto dto){
        return R.ok(postService.switchPost(dto));
    }


    @PostMapping(value = "/export")
    @ApiOperation(value = "导出")
    @XjrLog(value = "导出表单数据")
    public ResponseEntity<byte[]> export(@Valid @RequestBody Long deptId) {
        List<Post> list = postService.list(Wrappers.<Post>lambdaQuery().in(Post::getDeptId, deptId));
        List<PostExportVo> postExportVos = BeanUtil.copyToList(list, PostExportVo.class);
        ByteArrayOutputStream bot = new ByteArrayOutputStream();
        EasyExcel.write(bot).head(PostExportVo.class).automaticMergeHead(false)
                .registerWriteHandler(new FormContentStyleStrategy())
                .excelType(ExcelTypeEnum.XLSX).sheet().doWrite(postExportVos);
        ByteArrayOutputStream resultBot = ExcelUtil.renderExportRequiredHead(bot);
        return R.fileStream(resultBot.toByteArray(), "岗位导出" + ExcelTypeEnum.XLSX.getValue());
    }

    @GetMapping("/download-template")
    @ApiOperation(value = "下载模板")
    @SneakyThrows
    public ResponseEntity<byte[]> downloadTemplate() {
        List<PostExportVo> postExportVos = new ArrayList<>();
        ByteArrayOutputStream bot = new ByteArrayOutputStream();
        EasyExcel.write(bot).head(PostExportVo.class).automaticMergeHead(false)
                .registerWriteHandler(new FormContentStyleStrategy())
                .excelType(ExcelTypeEnum.XLSX).sheet().doWrite(postExportVos);
        ByteArrayOutputStream resultBot = ExcelUtil.renderExportRequiredHead(bot);
        return R.fileStream(resultBot.toByteArray(), "岗位导入模板" + ExcelTypeEnum.XLSX.getValue());
    }

    @PostMapping("/import")
    @ApiOperation(value = "导入")
    public R importData(@RequestParam MultipartFile file) throws IOException {
        List<PostExportVo> postExportVos = EasyExcel.read(file.getInputStream()).head(PostExportVo.class).sheet().doReadSync();
        List<Post> postList = BeanUtil.copyToList(postExportVos, Post.class);
        //获取所有的岗位
        List<Post> list = postService.list();
        for (Post post : postList) {
            List<Post> count = list.stream().filter(x -> x.getCode().equals(post.getCode())).collect(Collectors.toList());
            if (count.size() > 0){
                return R.error("导入的岗位编码已经存在！岗位名称为：" + post.getName());
            }
        }
        return R.ok(postService.saveBatch(postList));
    }
}
